package tr.edu.ozyegin.ccrg.raid.master;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import tr.edu.ozyegin.ccrg.raid.config.QuorumList;
import tr.edu.ozyegin.ccrg.raid.network.Client;
import tr.edu.ozyegin.ccrg.raid.network.Server;
import tr.edu.ozyegin.ccrg.raid.progressbar.ProgressBar;
import tr.edu.ozyegin.ccrg.raid.reader.FileReader;

public class Master implements Observer {
	protected ArrayList<Client>list = new ArrayList<Client>();
	protected Socket socket = null;
	protected QuorumList quorums = null;
	public Master(){
		
	}
	public boolean isInQuorum(String node){
		return this.quorums.isInQuorum(node);
	}
	public Master(String quorum){
		this.quorums = new QuorumList(quorum);
	}
	private Master(QuorumList quorum){
		this.quorums = quorum;
	}
	public boolean removeClient(){
		int size = this.list.size();
		Thread current = Thread.currentThread();
		for(int a = 0; a < size ; a++){
			Client node = this.list.get(a);
			if(node.equals(current)){
				return this.list.remove(node);
			}
		}
		return false;
	}
	public void addToList(Client node) {
		this.list.add(node);
	}
	public int getListSize() {
		for(int a = 0; a < this.list.size() ; a++){
			Client node = this.list.get(a);
			try {
				node.Write(new Short((short) 0));
			} catch (Exception e) {
				this.list.remove(a);
				node.Disconnect();
			}
		}
		return this.list.size();
		
	}
	public void brokeSequence(){
		for(int i =0; i < this.list.size(); i++){
			Client node = this.list.get(i);
			try {
				node.Write(new Short((short)3));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	public boolean writeFile(String fileName) throws IOException{
		File file = new File(fileName);
		if(!file.exists())return false;
		Master master = new Master(this.quorums);
		System.out.println("quorum size "+this.quorums.getQuorumSize());
		Server server  = new Server(2001);
		for(int i = 0 ; i < this.quorums.getQuorumSize(); i++){
			Client node = this.list.get(i);
			node.Write(new Short((short)2));//write opCode
			node.Write(new Integer(server.getPort()));//write the port no
			node.Write("conf"+System.getProperty("file.separator")+"sal"+i+".xml");//assuming the filename is correct
			
		}
		System.out.println("accepting the file");
		server.Accept(master, this.quorums.getQuorumSize());
		
		System.out.println("off the file");
		long length = file.length();
		int size = this.list.size();
		long ceiledChunk = Master.Ceil(length, size);
		ArrayList<Boolean> doneList = new ArrayList<Boolean>();
		ProgressBar progress = new ProgressBar(length);
		for(int i = 0; i < this.list.size() ; i++){
			doneList.add(new Boolean(false));
			long toWrite = ((length - (ceiledChunk*i)) < ceiledChunk)?(length - (ceiledChunk*i)):ceiledChunk;
			FileReader fr = new FileReader(fileName,doneList,(short)i,ceiledChunk*i,toWrite,master.list.get(i),progress);
			
			fr.addObserver(this);
			Thread th = new Thread(fr,"");
			th.start();
		}
		server.Close();
		
		return true;
	}
	public void CloseAll(){
		for(int i = 0 ; i < this.list.size() ; i++){
			Client node = this.list.get(i);
			try {
				node.Write(new Short((short)1));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	public static long Ceil(long num, int divisor){
		long reminder = num % divisor;
		if(reminder != 0)return ((long)(num/divisor))+1;
		return (long)(num/divisor);
	}
	@Override
	public void update(Observable arg0, Object arg1) {
		System.out.println("Send Completed");
	}
}
